package user_trip

import (
	"encoding/json"
	"sweetsunnyflower/app/http/dto/user"
	"sweetsunnyflower/app/requests"
	"sweetsunnyflower/pkg/app"
	"sweetsunnyflower/pkg/database"
	"sweetsunnyflower/pkg/paginator"

	"github.com/gin-gonic/gin"
	"github.com/golang-module/carbon/v2"
	"gorm.io/gorm"
)

func GetById(idstr string) (userTrip UserTrip) {
	database.DB.Preload("Car").Where("id", idstr).First(&userTrip)

	return
}

func Get(idstr string) (userTrip UserTrip) {
	database.DB.Preload("Start").
		Preload("End").
		Preload("Car").
		Preload("User").
		Preload("TripPassenger", func(db *gorm.DB) *gorm.DB {
			return db.Preload("User")
		}).
		Where("id", idstr).First(&userTrip)

	return
}

func FormatTrip(userTripModel UserTrip) (*user.UserTrip, error) {

	// 格式化数据
	userTrip := user.UserTrip{
		ID:        userTripModel.ID,
		UserID:    userTripModel.UserID,
		StartID:   userTripModel.StartID,
		EndID:     userTripModel.EndID,
		Time:      userTripModel.Time,
		Status:    userTripModel.Status,
		CarId:     userTripModel.CarId,
		Sites:     userTripModel.Sites,
		Remaining: userTripModel.Remaining,
		Price:     userTripModel.Price,
		Remark:    userTripModel.Remark,
		Line:      userTripModel.Line,
		Start:     userTripModel.Start,
		End:       userTripModel.End,
		Car:       userTripModel.Car,
		User:      userTripModel.User,
		CreatedAt: userTripModel.CreatedAt,
	}

	if len(userTripModel.TripPassenger) > 0 {
		for _, passenger := range userTripModel.TripPassenger {
			p := user.Passenger{}
			err := json.Unmarshal([]byte(passenger.Passenger), &p)
			if err != nil {
				return nil, err
			}
			t := user.Trip{}
			err = json.Unmarshal([]byte(passenger.Trip), &t)
			if err != nil {
				return nil, err
			}
			b := user.Booking{}
			err = json.Unmarshal([]byte(passenger.Booking), &b)
			if err != nil {
				return nil, err
			}
			tripPassenger := &user.TripPassenger{
				ID:        passenger.ID,
				TripID:    passenger.TripID,
				UserID:    passenger.UserID,
				Status:    passenger.Status,
				User:      passenger.User,
				Passenger: p,
				Trip:      t,
				Booking:   b,
				CreatedAt: passenger.CreatedAt,
			}
			userTrip.TripPassenger = append(userTrip.TripPassenger, tripPassenger)
		}
	}

	return &userTrip, nil
}

func GetBy(field, value string) (userTrip UserTrip) {
	database.DB.Where("? = ?", field, value).First(&userTrip)
	return
}

func All() (userTrips []UserTrip) {
	database.DB.Find(&userTrips)
	return
}

func IsExist(field, value string) bool {
	var count int64
	database.DB.Model(UserTrip{}).Where("? = ?", field, value).Count(&count)
	return count > 0
}

func Paginate(c *gin.Context, perPage int) (userTrips []UserTrip, paging paginator.Paging) {
	paging = paginator.Paginate(
		c,
		database.DB.Model(UserTrip{}),
		&userTrips,
		app.V1URL(database.TableName(&UserTrip{})),
		perPage,
	)
	return
}

func GetByLatestId(query requests.UserTripsQueryRequest) (userTrips []UserTrip) {

	model := database.DB.Preload("Start").Preload("End").Preload("Car")

	if query.Owner && query.UserID > 0 {
		model = model.Where("user_id = ?", query.UserID)
	}

	if query.Status > 0 {
		model = model.Where("status = ?", query.Status)
	}

	if query.StartID > 0 {
		model = model.Where("start_id = ?", query.StartID)
	}

	if query.EndID > 0 {
		model = model.Where("end_id = ?", query.EndID)
	}

	if query.LatestId > 0 {
		model = model.Where("id < ?", query.LatestId)
	}

	if query.Time != "" {
		model = model.Where("time >= ?", query.Time).Where("time < ?", carbon.Parse(query.Time).AddDay().ToDateTimeString())
	}

	model.Order("id desc").Limit(query.Limit).Find(&userTrips)

	return
}

func Count(query requests.UserTripsQueryRequest) (count int64) {
	model := database.DB.Model(&UserTrip{})

	if query.UserID > 0 {
		model = model.Where("user_id = ?", query.UserID)
	}

	if query.StartID > 0 {
		model = model.Where("start_id = ?", query.StartID)
	}

	if query.EndID > 0 {
		model = model.Where("end_id = ?", query.EndID)
	}

	if query.Time != "" {
		model = model.Where("time >= ?", query.Time).Where("time < ?", carbon.Parse(query.Time).AddDay().ToDateTimeString())
	}

	model.Count(&count)
	return
}
